package cn.xinfei.xdecision.common.service.component.dependency.impl;

import cn.xinfei.xdecision.common.model.component.dependency.EngineNodeComponentRel;
import cn.xinfei.xdecision.common.model.component.dependency.resp.DecisionComponentDependencyResp;
import cn.xinfei.xdecision.common.model.enginex.po.EngineNode;
import cn.xinfei.xdecision.common.service.component.dependency.AbstractDependency;
import cn.xinfei.xdecision.common.service.component.dependency.Dependency;
import cn.xinfei.xdecision.common.service.component.dependency.EngineNodeComponentRelService;
import cn.xinfei.xdecision.common.utils.constant.SysConstant;
import cn.xinfei.xdecision.common.utils.enums.enginex.EngineVersionStatusEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.NodeTypeEnum;
import cn.xinfei.xdecision.common.utils.exception.ApiException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.xinfei.xdecision.common.utils.constant.enginex.DecisionFlowCheckMessageConst.BASE_RULE_DECISION_FLOW_CYCLIC_DEPENDENCY;
import static cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum.DECISION_FLOW_CHECK_ERROR;


/**
 * 子引擎
 */
@Dependency(NodeTypeEnum.CHILD_ENGINE)
@Component
public class DecisionFlowDependency extends AbstractDependency {

    @Resource
    private EngineNodeComponentRelService engineNodeComponentRelService;

    @Override
    protected List<EngineNodeComponentRel> initData(final String nodeJson, final EngineNode engineNode) {
        if (StringUtils.isEmpty(nodeJson)) {
            return new ArrayList<>();
        }
        EngineNodeComponentRel engineNodeComponentRel = initData(engineNode)
                //组件code(子引擎的code)
                .setComponentCode(nodeJson)
                //子引擎更新节点时没有版本号
                .setComponentVersionNo(0L);
        //校验是否有环形（子引擎.子引擎 != 当前引擎）
        Set<String> engineCodeList = new HashSet<>();
        findAllParentEngineCodes(Collections.singletonList(engineNode.getEngineCode()), engineCodeList);
        if (engineCodeList.contains(nodeJson)) {
            throw new ApiException(DECISION_FLOW_CHECK_ERROR.getCode(), BASE_RULE_DECISION_FLOW_CYCLIC_DEPENDENCY);
        }
        return Collections.singletonList(engineNodeComponentRel);
    }

    /**
     * 查询全部父类引擎code
     */
    private void findAllParentEngineCodes(List<String> nodeCodes, Set<String> engineCodeList) {
        List<DecisionComponentDependencyResp> dependencyRespList = engineNodeComponentRelService
                .listByEngineNodeCodes(nodeCodes, NodeTypeEnum.CHILD_ENGINE.getCode(), EngineVersionStatusEnum.DISABLE.getStatus());
        if (CollectionUtils.isEmpty(dependencyRespList)) {
            return;
        }
        //子引擎
        List<String> collect = dependencyRespList.stream()
                .map(dependencyResp -> dependencyResp.getEngineNodeCode()
                        .substring(0, dependencyResp.getEngineNodeCode().lastIndexOf(SysConstant.UNDERLINE))).distinct()
                .collect(Collectors.toList());
        if (collect.stream().anyMatch(engineCodeList::contains)) {
            throw new ApiException(DECISION_FLOW_CHECK_ERROR.getCode(), BASE_RULE_DECISION_FLOW_CYCLIC_DEPENDENCY);
        }
        engineCodeList.addAll(collect);
        findAllParentEngineCodes(collect, engineCodeList);
    }
}
